package org.glutenberg.dao;

import java.io.IOException;
import java.util.Enumeration;
import java.util.Hashtable;
import java.util.Vector;

import org.glutenberg.model.Brand;
import org.glutenberg.model.Category;
import org.glutenberg.model.Product;
import org.glutenberg.util.Map;
import org.glutenberg.util.RandomAccessStreamReader;
import org.glutenberg.util.StringUtils;
import org.glutenberg.util.TreeMap;

public class ProductReader {
	
	private RandomAccessStreamReader reader;
	private Vector indexes;
	private long reverseIndexEnd;

	public ProductReader(ReverseIndex reverseIndex, RandomAccessStreamReader reader, Vector indexes){
		this.reader = reader;
		this.indexes = indexes;
		this.reverseIndexEnd = reverseIndex.getEndIndex();
	}
	
	private Product readProduct(long index) throws IOException{
		Product ret = new Product();
		this.reader.seek(this.reverseIndexEnd + index);
		char c = (char)this.reader.read();
		if(c!='3') return null;
		StringBuffer sb = new StringBuffer();
		char spiga = (char)this.reader.read();
		char ministero = (char)this.reader.read();
		char grossista = (char)this.reader.read();
		ret.setSpiga(spiga == '1');
		ret.setMinistero(ministero == '1');
		ret.setGrossista(grossista == '1');
		c = (char)this.reader.read();
		while(c!='§'){
			sb.append(c);
			c = (char)this.reader.read();
		}
		ret.setName(sb.toString());
		sb = new StringBuffer();
		c = (char)this.reader.read();
		while(c!='§'){
			sb.append(c);
			c = (char)this.reader.read();
		}
		try{
			ret.setCategoryIndex(Long.parseLong(sb.toString()));
		} catch(NumberFormatException e){}
		sb = new StringBuffer();
		c = (char)this.reader.read();
		while(c!='\n'){
			sb.append(c);
			c = (char)this.reader.read();
		}
		try{
			ret.setBrandIndex(Long.parseLong(sb.toString()));
		} catch(NumberFormatException e){}
		return ret;
	}
	
	private Category readCategory(long index) throws IOException{
		this.reader.seek(this.reverseIndexEnd + index);
		char c = (char)this.reader.read();
		if(c!='1') return null;
		StringBuffer sb = new StringBuffer();
		c = (char)this.reader.read();
		while(c!='\n' && c>=0){
			sb.append(c);
			c = (char)this.reader.read();
		}
		if(c<0) return null;
		Vector names = StringUtils.split(sb.toString(), ",");
		Category ret = new Category();
		if(names.size()>0) ret.setName((String)names.elementAt(0));
		if(names.size()>1) ret.setEnglishName((String)names.elementAt(1));
		return ret;
	}
	
	private Brand readBrand(long index) throws IOException {
		this.reader.seek(this.reverseIndexEnd + index);
		char c = (char)this.reader.read();
		if(c!='2') return null;
		StringBuffer sb = new StringBuffer();
		c = (char)this.reader.read();
		while(c!='\n' && c>=0){
			sb.append(c);
			c = (char)this.reader.read();
		}
		if(c<0) return null;
		String name = sb.toString();
		Brand ret = new Brand();
		ret.setName(name);
		return ret;	
	}
	
	private void readCategoriesAndBrands(Vector products) throws IOException{
		TreeMap categories = new TreeMap();
		TreeMap brands = new TreeMap();
		for(int i=0;i<products.size();i++){
			Product p = (Product)products.elementAt(i);
			long categoryIndex = p.getCategoryIndex();
			long brandIndex = p.getBrandIndex();
			categories.put(new IndexRecord(categoryIndex), null);
			brands.put(new IndexRecord(brandIndex), null);
		}
		Enumeration categoryKeys = categories.elements();
		while(categoryKeys.hasMoreElements()){
			Map.Entry entry = (Map.Entry)categoryKeys.nextElement();
			IndexRecord r = (IndexRecord)entry.getKey();
			Category cat = this.readCategory(r.getIndex());
			categories.put(r, cat);
		}
		Enumeration brandKeys = brands.elements();
		while(brandKeys.hasMoreElements()){
			Map.Entry entry = (Map.Entry)brandKeys.nextElement();
			IndexRecord r = (IndexRecord)entry.getKey();
			Brand brand = this.readBrand(r.getIndex());
			brands.put(r, brand);
		}
		for(int i=0;i<products.size();i++){
			Product p = (Product)products.elementAt(i);
			Category cat = (Category)categories.get(new IndexRecord(p.getCategoryIndex()));
			Brand brand = (Brand)brands.get(new IndexRecord(p.getBrandIndex()));
			p.setCategory(cat);
			p.setBrand(brand);
		}
	}

	public Vector readProducts(int offset, int limit) throws IOException{
		if(offset>=this.indexes.size()) return new Vector();
		else {
			Vector ret = new Vector();
			for(int i = offset; i<offset+limit && i<this.indexes.size(); i++){
				long index = ((Long)this.indexes.elementAt(i)).longValue();
				Product p = this.readProduct(index);
				if(p!=null) ret.addElement(p);
			}
			this.readCategoriesAndBrands(ret);
			return ret;
		}
	}
	
	public int size(){
		return this.indexes.size();
	}
}
